package com.lutzyt.delivery.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lutzyt.delivery.bean.*;
import com.lutzyt.delivery.bean.vo.MenuTree;
import com.lutzyt.delivery.mapper.MenuDAO;
import com.lutzyt.delivery.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zyt
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class MenuServiceImpl extends ActionServiceImpl<MenuDAO, Menu> implements MenuService {

  public static final String MENU_ID = "menu_id";
  private MenuDAO menuDAO;
  private UserService userService;
  private UserRoleService userRoleService;
  private RolePermissionService rolePermissionService;
  private PermissionMenuService permissionMenuService;


  @Override
  @Transactional(readOnly = true)
  public Menu findById(Integer id) {
    return menuDAO.selectById(id);
  }

  @Override
  @Transactional(readOnly = true)
  public Page<Menu> findByPage(int pageNum, int pageSize) {
    final List<Menu> list = query()
        .eq("type", "directory")
        .eq("deleted", "0").list();
    final Map<Integer, Menu> menuMap = this.getMenuMap(list);
    final Page<Menu> menuPage = menuDAO.selectPage(new Page<>(pageNum, pageSize), null);
    for (Menu menu : menuPage.getRecords()) {
      if (menu.getParent() != null){
        Menu parentMenu = menuMap.get(menu.getParent());
        menu.setParentCode(parentMenu.getCode());
        menu.setParentName(parentMenu.getName());
      } else {
        menu.setParentCode("0000");
        menu.setParentName("/");
      }
    }
    return menuPage;
  }

  @Override
  public void insert(Menu menu) {
    // 存在未删除的code值
    final List<Menu> code = query().eq("deleted", 0).eq("code", menu.getCode()).list();
    if (code.size() > 0) {
      throw new RuntimeException("该code值已存在，请重新输入");
    }
    menuDAO.insert(menu);
  }

  @Override
  public void update(Menu menu) {
    menuDAO.updateById(menu);
  }

  @Override
  public void deleteById(Integer id) {
    if (permissionMenuService.query().eq(MENU_ID, id).count() > 0) {
      throw new RuntimeException("该菜单已经被使用，删除失败");
    }
    menuDAO.deleteById(id);
  }

  @Override
  public void deleteByIds(List<String> ids) {
    if (permissionMenuService.query().in(MENU_ID, ids).count() > 0) {
      throw new RuntimeException("删除的菜单中含有被使用的菜单，删除失败");
    }
    menuDAO.deleteBatchIds(ids);
  }

  @Override
  public List<Menu> parentList() {
    final List<Menu> list = query()
        .eq("type", "directory")
        .eq("deleted", "0").list();
    final Map<Integer, Menu> menuList = getMenuMap(list);
    return new ArrayList<>(menuList.values());
  }

  private Map<Integer, Menu> getMenuMap(List<Menu> list) {
    final Map<Integer, Menu> menuList = list.stream().collect(Collectors.toMap(Menu::getId, Function.identity()));
    menuList.forEach((k,v)->{
      if (v.getParent() == null){
        v.setParentCode("0000");
        v.setParentName("/");
        v.setName("/"+v.getName());
        parentList(k, menuList);
      }
    });
    return menuList;
  }

  /**
   * 递归处理所有菜单的名称，并且添加父菜单名称
   * @param id 父菜单id
   * @param menuList 菜单 map
   */
  private void parentList(Integer id, Map<Integer, Menu> menuList){
    menuList.forEach((k,v)->{
      if (v.getParent() != null && v.getParent().equals(id)){
        v.setParentName(menuList.get(id).getName());
        v.setParentCode(menuList.get(id).getCode());
        v.setName(v.getParentName()+"/"+v.getName());
        parentList(k, menuList);
      }
    });
  }

  @Override
  public List<MenuTree> menuTree() {
    final List<Menu> menuList = query().eq("deleted", "0").list();
    return MenuTree.newTreeList(menuList);
  }

  @Override
  public List<MenuTree> getByUsername(String username) {
    final List<MenuTree> menuTrees = this.menuTree();
    if ("admin".equals(username)){
      return menuTrees;
    }
    User user = userService.findByName(username);
    final UserRole userRole = userRoleService.findById(user.getId());
    final List<Integer> permissionIds = rolePermissionService.findPermissionIdByIds(userRole.getRoleIds());
    final List<Integer> menuIds = permissionMenuService.findMenuIdByIds(permissionIds);
    final List<Menu> list = this.query().in("id", menuIds).eq("deleted", 0).list();
    return MenuTree.newTreeList(list);
  }

  @Autowired
  public void setMenuDAO(MenuDAO menuDAO) {
    this.menuDAO = menuDAO;
  }

  @Autowired
  public void setPermissionMenuService(PermissionMenuService permissionMenuService) {
    this.permissionMenuService = permissionMenuService;
  }

  @Autowired
  public void setUserRoleService(UserRoleService userRoleService) {
    this.userRoleService = userRoleService;
  }

  @Autowired
  public void setRolePermissionService(RolePermissionService rolePermissionService) {
    this.rolePermissionService = rolePermissionService;
  }

  @Autowired
  public void setUserService(UserService userService) {
    this.userService = userService;
  }
}